<?php
declare(strict_types=1);

namespace App\Utils\Other\Payment\Sumpay;

use App\Exception\InternalException;
use App\Utils\Other\Payment\Base;
use App\Utils\Http\Request;
use Hyperf\Collection\Arr;
use function App\Utils\Common\SumpayRsa\verify;
use function Hyperf\Support\make;
use function App\Utils\Common\SumpayRsa\generate;
use function App\Utils\Common\SumpayRsa\processJsonArrayFields;
use function App\Utils\Common\SumpayRsa\encryptByAesKey;
use function App\Utils\Common\SumpayRsa\encrypt as rsaEncrypt;
use function App\Utils\Common\SumpayRsa\specialChange;
use function App\Utils\Common\SumpayRsa\sign;
use function App\Utils\Common\SumpayRsa\splic;
use function Hyperf\Translation\__;
use function App\Utils\Common\SumpayRsa\charsetChange;

/**
 * Class App
 * @package App\Utils\Other\Payment\Sumpay
 */
abstract Class App extends Base {

    /**
     * 参数拼接
     * @param array $params
     * @return array
     * @throws \Exception
     */
    protected function params(array $params = []): array
    {
        $params['version'] = '1.0';
        $params['format'] = 'JSON';
        $params['app_id'] = $this->getConfig('mer_app_id');
        $params['timestamp'] = date('YmdHis');
        $params['terminal_type'] = 'api';
        $aesKey = generate();

        $data = processJsonArrayFields(
            $params, $aesKey, $this->getConfig('encrypt_fields'),
            $this->getConfig('json_fields'), $this->getConfig('special_fields')
        );
        $data = charsetChange($data);
        $data = encryptByAesKey($data, $aesKey, $this->getConfig('encrypt_fields'));
        logs($this->getConfig('public_cert_path'));
        $aesKey = rsaEncrypt(base64_encode($aesKey), $this->getConfig('public_cert_path'));
        $data['aes_key'] = $aesKey;
        $data = specialChange($data, $this->getConfig('special_fields'));
        logs($data);

        $data['sign'] = sign(splic($data), $this->getConfig('private_cert_path'), $this->getConfig('password'));
        $data['sign_type'] = 'CERT';

        return $data;
    }

    /**
     * 发起请求
     * @param array $params
     * @return array
     */
    protected function request(array $params = []): array
    {
        // TODO: Implement request() method.
        /** @var Request $request */
        $request = make(Request::class);

        $params = $this->params($params);
        $response = $request
            ->setHeaders(['Referer' => getDomain()])
            ->setOptions([CURLOPT_SSLVERSION => CURL_SSLVERSION_TLSv1_2])
            ->post($this->getConfig('url'), $params);

        return $this->response($response, $params);
    }

    /**
     * 响应处理
     * @param $response
     * @param array $params
     * @return array
     */
    protected function response($response, array $params = []): array
    {
        logs($response);
        if (!$response) {
            throw new InternalException(__('request.nobody'));
        }
        $result = json_decode($response, true);
        $jsonError = json_last_error();
        if ($jsonError !== JSON_ERROR_NONE) {
            throw new InternalException(__('request.json_error', [
                'code' => $jsonError,
                'message' => json_last_error_msg()
            ]));
        }

        if (Arr::get($result, 'resp_code') !== '000000') {
            throw new InternalException(__('request.error', [
                'code' => Arr::get($result, 'resp_code'),
                'message' => Arr::get($result, 'resp_msg')
            ]));
        }

        $sign = $result['sign'];
        unset($result['sign']);
        unset($result['sign_type']);
        $data = splic($result);
        verify($data, $sign, $this->getConfig('public_cert_path'));

        return [$params, $result, $result];
    }

}